﻿#include "FITKSEASubSysShellCurved.h"
#include "FITKAcousticsDiscModel.h"
#include "FITKAcousticsSEAModel.h"
#include "FITKAcousticsDiscNodeList.h"
#include "FITKAbstractSEAFace.h"
#include "FITKSEAFlatCurvedFace.h"
#include "FITKAcousticsTriangles.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementFactory.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementTri.h"
#include "FITK_Component/FITK2DMeshTools/FITKTriMeshGenEarCut.h"

namespace Acoustics
{
    FITKAbstractSEASubSys::SEASubSysType Acoustics::FITKSEASubSysSinglyCurvedShell::getSEASubSysType()
    {
        return FITKAbstractSEASubSys::SEASubSysType::SEASinglyCurvedShell;
    }
    /**     4个拐点与拐点相邻的连接点形成4个三角形
     *      中间的连接点与对侧连接点相连，形成多个矩形区域，每个矩形区域可以划分2个三角形
     *      1、2拐点之间的连接点与其相邻的一个连接点，组成多边形区域
     *      3、4拐点之间的连接点与其相邻的一个连接点，组成多边形区域
     *   1 * * * * * * * * * * * * * * 4
     *     *       *     *           *
     *     *       *     *           *
     *     *       *     *           *
     *   2 * * * * * * * * * * * * * * 3
     */
    bool FITKSEASubSysSinglyCurvedShell::updateTriMesh()
    {
        //获取离散数据
        Acoustics::FITKAcousticsDiscModel* discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (!discModel)return false;
        //获取节点管理器
        Acoustics::FITKAcousticsDiscNodeList* discNodesList = discModel->getNodes();
        if (!discNodesList)return false;
        //记录拐点数据
        
        auto nodes = this->getNodes();
        auto triMesh = this->getTriangleMesh();
        if (nodes.isEmpty() || triMesh == nullptr) return false;


        QList<int> cornerPointIndexList;
        for (int i = 0; i < nodes.size(); ++i)
        {
            //获取拐点Index
            FITKAbstractSEASubSysWithNodes::SubSysNodeType type = nodes.at(i)._type;
            if (type == FITKAbstractSEASubSysWithNodes::SubSysNodeType::Start || type == FITKAbstractSEASubSysWithNodes::SubSysNodeType::Corner)
                cornerPointIndexList.append(i);
        }
        //拐点数据判断
        if (cornerPointIndexList.size() != 4)return false;
        //每个拐点之间必须要有连接点
        if (cornerPointIndexList.at(1) - cornerPointIndexList.at(0) <= 1)return false;
        if (cornerPointIndexList.at(2) - cornerPointIndexList.at(1) <= 1)return false;
        if (cornerPointIndexList.at(3) - cornerPointIndexList.at(2) <= 1)return false;
        if (nodes.size() - cornerPointIndexList.at(3) <= 0)return false;
        //根据第2、3拐点与1、4拐点之间的路径上的点要保持一致
        if (cornerPointIndexList.at(2) - cornerPointIndexList.at(1) != nodes.size() - cornerPointIndexList.at(3))return false;
        //根据拐点生成三角网格
        for (int i = 0; i < cornerPointIndexList.size(); ++i)
        {
            //获取拐点
            int cornerPointIndex = cornerPointIndexList.at(i);
            Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode cornerPoint = nodes.at(cornerPointIndex);
            //获取上一个节点和下一个节点
            Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode previousNode = nodes.last();
            Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode nextNode = nodes.first();
            if (cornerPointIndex > 0)
                previousNode = nodes.at(cornerPointIndex - 1);
            if (cornerPointIndex + 1 < nodes.size())
                nextNode = nodes.at(cornerPointIndex + 1);
            //判断拐点的上一个节点和下一个节点的类型是否是终点或路径上的点
            if (!(previousNode._type == FITKAbstractSEASubSysWithNodes::SubSysNodeType::Path || previousNode._type == FITKAbstractSEASubSysWithNodes::SubSysNodeType::Finish))return false;
            if (!(nextNode._type == FITKAbstractSEASubSysWithNodes::SubSysNodeType::Path || nextNode._type == FITKAbstractSEASubSysWithNodes::SubSysNodeType::Finish))return false;
            //拐点创建三角单元
            Interface::FITKAbstractElement* element = Interface::FITKElementFactory::createElement(Interface::FITKModelEnum::FITKEleType::Tri3);
            element->setNodeID(QList<int>() << previousNode._id << cornerPoint._id << nextNode._id);
            triMesh->appendElement(element);
        }
        //根据第2、3拐点与1、4拐点之间的路径上的点创建三角形网格
        int num = nodes.size() - cornerPointIndexList.at(3) - 2;
        for (int i = 0; i < num; ++i)
        {
            Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode point3 = nodes.at(cornerPointIndexList.at(3) + 1 + i);
            Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode point4 = nodes.at(cornerPointIndexList.at(3) + 2 + i);
            Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode point2 = nodes.at(cornerPointIndexList.at(2) - 1 - i);
            Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode point1 = nodes.at(cornerPointIndexList.at(2) - 2 - i);
            //根据矩形创建两个三角单元
            Interface::FITKAbstractElement* element1 = Interface::FITKElementFactory::createElement(Interface::FITKModelEnum::FITKEleType::Tri3);
            element1->setNodeID(QList<int>() << point1._id << point2._id << point3._id);
            triMesh->appendElement(element1);
            Interface::FITKAbstractElement* element2 = Interface::FITKElementFactory::createElement(Interface::FITKModelEnum::FITKEleType::Tri3);
            element2->setNodeID(QList<int>() << point3._id << point4._id << point1._id);
            triMesh->appendElement(element2);
        }
        //将去除拐点的围城多边形的区域进行划分三角形网格
        //获取第1、2拐点相邻的2个连接点
        int nodePath1Index = nodes.size() - 1;
        int nodePath2Index = cornerPointIndexList.at(1) + 1;
        Core::FITKNode* nodePath1 = discNodesList->getNodeByID(nodes.at(nodePath1Index)._id);
        Core::FITKNode* nodePath2 = discNodesList->getNodeByID(nodes.at(nodePath2Index)._id);
        if (!nodePath1 || !nodePath2) return false;
        //划分第1、2拐点与连接点划分的区域
        QList<Core::FITKNode*> nodesList1;
        for (int i = cornerPointIndexList.at(0) + 1; i < cornerPointIndexList.at(1); ++i)
        {
            Core::FITKNode* nodePath = discNodesList->getNodeByID(nodes.at(i)._id);
            if (!nodePath1)continue;
            nodesList1.append(nodePath);
        }
        nodesList1.append(nodePath2);
        nodesList1.append(nodePath1);
        //生成三角形网格
        Interface::FITKTriMeshGenEarCut triMeshGen1;
        triMeshGen1.setPointList(nodesList1);
        if (!triMeshGen1.generateMesh())return false;
        QList<Interface::FITKAbstractElement*> elementList = triMeshGen1.getTriangle();
        for (Interface::FITKAbstractElement* elem : elementList)
            triMesh->appendElement(elem);
        //获取第3、4拐点相邻的2个连接点
        nodePath1Index = cornerPointIndexList.at(3) + 1;
        nodePath2Index = cornerPointIndexList.at(2) - 1;
        nodePath1 = discNodesList->getNodeByID(nodes.at(nodePath1Index)._id);
        nodePath2 = discNodesList->getNodeByID(nodes.at(nodePath2Index)._id);
        if (!nodePath1 || !nodePath2) return false;
        //划分第1、2拐点与连接点划分的区域
        QList<Core::FITKNode*> nodesList2;
        nodesList2.append(nodePath2);
        for (int i = cornerPointIndexList.at(2) + 1; i < cornerPointIndexList.at(3); ++i)
        {
            Core::FITKNode* nodePath = discNodesList->getNodeByID(nodes.at(i)._id);
            if (!nodePath1)continue;
            nodesList2.append(nodePath);
        }
        nodesList2.append(nodePath1);
        //生成三角形网格
        Interface::FITKTriMeshGenEarCut triMeshGen2;
        triMeshGen2.setPointList(nodesList2);
        if (!triMeshGen2.generateMesh())return false;
        elementList = triMeshGen2.getTriangle();
        for (Interface::FITKAbstractElement* elem : elementList)
            triMesh->appendElement(elem);
        return true;
    }

    Acoustics::FITKAbstractSEASubSys::SEASubSysType FITKSEASubSysDoublyCurvedShell::getSEASubSysType()
    {
        return FITKAbstractSEASubSys::SEADoublyCurvedShell;
    }

    void FITKSEASubSysDoublyCurvedShell::setNumberOfRing(const int nRing)
    {
         FITKSEADoublyCurvedFace* df = dynamic_cast<FITKSEADoublyCurvedFace*> (this->getFaceObj());
         //不存在face，创建face
         if (df == nullptr)
             this->setNodes(QList<FITKAbstractSEASubSysWithNodes::SubSysNode>());
         //再次获取
         df = dynamic_cast<FITKSEADoublyCurvedFace*> (this->getFaceObj());
         if (df) df->setNumberOfRing(nRing);
    }

    int FITKSEASubSysDoublyCurvedShell::getNumberOfRing() const
    {
        //获取face
        FITKSEADoublyCurvedFace* df = dynamic_cast<FITKSEADoublyCurvedFace*> (this->getFaceObj());
        if (df) return df->getNumberOfRing();
        return -1;
    }
    /**
     *    按最后一层为一个节点，其他层均分节点，划分三角形
     */
    bool FITKSEASubSysDoublyCurvedShell::updateTriMesh()
    {
        int numberOfRing = this->getNumberOfRing();

        if (numberOfRing <= 0)return false;
        //获取离散数据
        Acoustics::FITKAcousticsDiscModel* discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (!discModel)return false;
        //获取节点管理器
        Acoustics::FITKAcousticsDiscNodeList* discNodesList = discModel->getNodes();
        if (!discNodesList)return false;
       
        auto nodes = this->getNodes();
        auto triMesh = this->getTriangleMesh();
        if (nodes.isEmpty() || triMesh == nullptr) return false;


        //判断其他层是否均分
        if ((nodes.size() - 1) % numberOfRing != 0)return false;
        int nodeFringeCount = (nodes.size() - 1) / numberOfRing;
        if (nodeFringeCount < 3)return false;
        //划分边沿的层的三角形网格
        for (int i = 0; i < numberOfRing - 1; ++i)
        {
            for (int j = 0; j < nodeFringeCount; ++j)
            {
                //获取4个节点组成的矩形
                int index1 = i * nodeFringeCount + j;
                int index2 = i * nodeFringeCount + j + 1;
                if (j + 1 == nodeFringeCount)
                    index2 = i * nodeFringeCount;
                int index3 = (i + 1) * nodeFringeCount + j;
                int index4 = index3 - 1;
                if (j == 0)
                    index4 = (i + 1) * nodeFringeCount + nodeFringeCount - 1;
                //根据矩形创建两个三角单元
                Interface::FITKAbstractElement* element1 = Interface::FITKElementFactory::createElement(Interface::FITKModelEnum::FITKEleType::Tri3);
                element1->setNodeID(QList<int>() << nodes.at(index1)._id << nodes.at(index2)._id << nodes.at(index3)._id);
                triMesh->appendElement(element1);
                Interface::FITKAbstractElement* element2 = Interface::FITKElementFactory::createElement(Interface::FITKModelEnum::FITKEleType::Tri3);
                element2->setNodeID(QList<int>() << nodes.at(index1)._id << nodes.at(index3)._id << nodes.at(index4)._id);
                triMesh->appendElement(element2);
            }
        }
        //获取顶点的数据
        Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode pointLast = nodes.last();
        //划分最后一层的三角形网格
        for (int i = 0; i < nodeFringeCount; ++i)
        {
            int index1 = (numberOfRing - 1) * nodeFringeCount + i;
            int index2 = (numberOfRing - 1) * nodeFringeCount + i + 1;
            if (index2 + 1 == nodes.size())
                index2 = (numberOfRing - 1) * nodeFringeCount;
            //获取点数据
            Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode point1 = nodes.at(index1);
            Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode point2 = nodes.at(index2);
            Interface::FITKAbstractElement* element = Interface::FITKElementFactory::createElement(Interface::FITKModelEnum::FITKEleType::Tri3);
            element->setNodeID(QList<int>() << point1._id << point2._id << pointLast._id);
            triMesh->appendElement(element);
        }
        return true;
    }
}

